﻿// ## 2024/02/28 # 铃 # AI势力/军团的全局战略选择,优先级高于城市 ##

namespace AI_ATTACK_WEIGHT
{
    class base_weight
    {
        int base_id;
        int 地图战略分;
        int 战斗力分;
        int 人口资源分;
        int 势力分;
        int 战略威胁分;
        int 球形分;

    };


    class Main
    {

        pk::c_bool 调试模式 = pk::c_bool(false);
        array<int32> weight(据点_末, 0);
        base_weight base_weight;

        Main()
        {
            //pk::bind(111, pk::trigger111_t(onTurnStart));
            pk::bind(260, pk::trigger260_t(AI战略选择_798_打印));
        }

        void AI战略选择_798_打印()
        {
            ImGui::Checkbox("调试模式", 调试模式);
        }

        pk::building @final_base;

        void onTurnStart(pk::force @force)
        {
            int force_id = force.get_id();

            if (force.get_id() != pk::get_current_turn_force_id()) return;

            if (pk::is_normal_force(force_id) and pk::get_elapsed_months() > 6)
            {
                calc_weight(force);
            }
            return;
        }


        pk::list<pk::building @>  calc_weight(pk::force @force)
        {

            pk::list<pk::building @> building_list;
            pk::list<pk::building @> building_list_final;
            int src_force_id = force.get_id();
            int count_in_line = 0;

            //pk::trace(pk::format("func_263,{},打印开关{}", pk::decode(pk::get_name(building)),调试模式.v));
            if (force.is_player())
                return building_list;

            // ********************************* 初始化- 获取周边据点列表 *******************************************


            //清空
            for (int i = 0; i < 据点_末; i++)
            {
                weight[i] = 0;
            }


            //计算己方有几个前线城池
            for (int i = 0; i < 据点_末; i++)
            {
                if (pk::get_building(i).get_force_id() != force.get_id())
                    continue;
                if (ai::base_in_line_level[i] == 1 and i < 城市_末) count_in_line += 2;
                if (ai::base_in_line_level[i] == 1 and i >= 城市_末) count_in_line++;
            }




            //所有和己方接壤的城市
            for (int i = 0; i < 据点_末; i++)
            {
                if (pk::get_building(i).get_force_id() != force.get_id())
                    continue;
                for (int j = 0; j < 据点_末; j++)
                {
                    if (i == j) continue;
                    if (pk::is_enemy(pk::get_building(i), pk::get_building(j)) and pk::get_building_distance(i, j) == 1)
                        building_list.add(pk::get_building(j));
                }
            }

            if (building_list.count <= 0)
                return building_list;


            if (调试模式.v)
                pk::trace(" 遍历开始:" + pk::decode(pk::get_name(force)) + "  军");





            for (int i = 0; i < building_list.count; ++i)
            {
                pk::building @dst_base = building_list[i];
                int dst_id = dst_base.get_id();

                int dst_force_id = dst_base.get_force_id();
                pk::force @dst_force = pk::get_force(dst_force_id);

                if (!pk::is_alive(dst_base))
                    continue;


                      // ********************************* 据点相关:据点战斗力*****************************************
                int 目标总防御能力;
                int 目标野战战斗力 = ai::base_atk_power[dst_id];
                int 目标守城战斗力 = ai::base_def_power[dst_id] + ch::base_enemy_not_from_force(dst_base, force);
                int 目标大城野战战斗力 = 0;
                int 支援部队战斗力 = 0;

            // 小城市和关卡还要考虑所在的同势力的大城战斗力
                if (dst_base.get_force_id() == pk::get_city(pk::get_city_id(dst_base.pos)).get_force_id() and dst_base.facility != 设施_都市)
                {
                    pk::building @dst_base_city = pk::get_building(pk::get_city(pk::get_city_id(dst_base.pos)).get_id());
                    目标大城野战战斗力 = ai::base_atk_power[dst_base_city.get_id()];;

                }

                auto dst_force_near_building_list = ai::base_near_baselist[dst_id];
                for (int j = 0; j < dst_force_near_building_list.count; j++)
                {
                    int neighbor_force_base_id = dst_force_near_building_list[j].get_id();
                    if (neighbor_force_base_id == -1 or neighbor_force_base_id >= 据点_末)
                        continue;

                    if (dst_force_near_building_list[j].get_force_id() != dst_base.get_force_id())
                        continue;

                    if (pk::get_building_distance(neighbor_force_base_id, dst_id, dst_force_near_building_list[j].get_force_id()) > 1)
                        continue;
                    支援部队战斗力 += ai::base_atk_power[neighbor_force_base_id];

                }
                目标总防御能力 = 目标野战战斗力 + 目标守城战斗力 + 支援部队战斗力;

                weight[dst_id] += 50 - pk::min(目标总防御能力 / 5, 100);

                if (调试模式.v)
                    pk::trace(" 目标战力:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "  目标总防御能力:" + 目标总防御能力 + "  目标野战战斗力:" + 目标野战战斗力 + "  目标守城战斗力:" + 目标守城战斗力 + "  支援部队战斗力:" + 支援部队战斗力);


                // ********************************* 地图战略****************************************
                int 边缘值 = int(abs(dst_base.pos.x - 100) + abs(dst_base.pos.y - 100));

                if (边缘值 > 75)
                    weight[dst_id] += pk::min((边缘值 - 70), 30);  //有意错开,给边缘城市加底分

                if (调试模式.v)
                    pk::trace(" 地图战略:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "边缘值:" + 边缘值);


                // ********************************* 地优先攻击仅剩一个据点的势力,抢夺人才****************************************
                //仅剩一个据点+100分 1个城市+50分.
                if (ch::get_base_list(pk::get_force(dst_base.get_force_id())).count == 1)
                    weight[dst_id] += 50;


                if (pk::get_city_list(pk::get_force(dst_base.get_force_id())).count <= 1)
                    weight[dst_id] += 50;

                if (调试模式.v)
                    pk::trace(" 势力捡漏:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "边缘值:" + 边缘值);


                // ********************************* 地图战略 .州****************************************
                int dst_province_id = pk::get_province_id(dst_base.pos);
                if (dst_province_id == 州_幽州 or dst_province_id == 州_益州 or dst_province_id == 州_荆南 or dst_province_id == 州_凉州)
                    weight[dst_id] += 50;

                if (dst_province_id == 州_扬州 or dst_province_id == 州_南中)
                    weight[dst_id] += 30;

                if (调试模式.v)
                    pk::trace(" 州郡战略:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "目标州:" + dst_province_id);


                // ********************************* 据点相关:人口资源导向*****************************************
                // 目标城市的人口越多,权重越高.
                // 100万人口城市+3,20万人口城市-3.

                auto base_t = ch::get_base_p(dst_id);
                int 人口权重 = (int(base_t.population) - 30 * 10000) / 50000;

                weight[dst_id] += pk::max(0, 人口权重);

                if (调试模式.v)
                    pk::trace(" 人口修正:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "  人口权重:" + 人口权重);


                //********************************************************************************************************
                // *********************************球形战略选择*****************************************
                //********************************************************************************************************

                auto dst_neibor_building_list = ai::base_neibor_baselist[dst_id];
                int count = 0;
                for (int j = 0; j < dst_neibor_building_list.count; j++)
                {
                    int neighbor_base_id = dst_neibor_building_list[j].get_id();
                    if (neighbor_base_id == -1 or neighbor_base_id >= 据点_末)
                        continue;

                    if (dst_neibor_building_list[j].get_force_id() != src_force_id)
                        continue;

                    if (dst_neibor_building_list[j].get_id() < 城市_末) count += 2;
                    if (dst_neibor_building_list[j].get_id() >= 城市_末) count += 1;

                    weight[dst_id] += dst_neibor_building_list[j].troops / 1000;
                }

                weight[dst_id] += int(float(count) / float(count_in_line) * 100);

                if (调试模式.v)
                    pk::trace(" 球形战略:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "  比例:" + float(count) / float(count_in_line));

                // ********************************* 势力相关:势力排名*****************************************

                int src_rank = ai::force_list.index_of(pk::get_force(force.get_id()));
                int dst_rank = ai::force_list.index_of(pk::get_force(dst_base.get_id()));
                int force_count = ai::force_list.count;
                int rank_diff = dst_rank - src_rank;  //进攻方领先多少排名.

                // 尽量避免和大势力对抗

                if ((dst_force_id == -1 or dst_force_id >= 势力_末))
                    dst_rank = force_count;

                else
                {
                    int count_neibor_enemy_force = 0;
                    for (int h = 0; h < 非贼势力_末; h++)
                    {
                        if (ai::force_to_force_enemy_base[src_force_id][h] > 0) count_neibor_enemy_force++;
                    }

                    if (ai::force_to_force_enemy_base[src_force_id][dst_force_id] <= 3 and dst_rank < 2 and force_count > 3 and count_neibor_enemy_force > 2)
                    {
                        if (调试模式.v)
                            pk::trace(" 相邻少大势力:目的地:" + pk::decode(pk::get_name(dst_base)) + "  不招惹相邻不多的大势力:" + ai::force_to_force_enemy_base[src_force_id][dst_force_id]);
                        continue;
                    }


                    if (调试模式.v)
                        pk::trace(" 相邻城市数量:目的地:" + pk::decode(pk::get_name(dst_base)) + "  相邻城市数量:" + ai::force_to_force_enemy_base[src_force_id][dst_force_id] + "  " + src_force_id + " " + dst_force_id);

                    if (ai::force_to_force_enemy_base[src_force_id][dst_force_id] <= 2 and dst_rank < 3 and force_count > 3 and count_neibor_enemy_force > 2)
                        weight[dst_id] += int(dst_rank * 60.0 / force_count);
                        //weight[dst_id] += int(rank_diff * 10.0 / force_list.count);
                }
                // 尽量不去招惹最强的势力,比如说7个势力的时候,不要去打最强的那两个
                if (force_count > 6 and (dst_rank <= force_count / 5 or dst_rank <= 1) and !dst_base.is_player())
                {
                    if (src_rank <= 1) weight[dst_id] -= 150;
                    else weight[dst_id] -= 200;
                }

                if (调试模式.v)
                    pk::trace(" 势力相关:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "  目标排名" + dst_rank + "  排名差" + rank_diff + "  势力总数" + force_count);

                //********************************************************************************************************
                // *********************************特别重要!!!!!!:战略选择*****************************************
                //********************************************************************************************************

                // 如果一个目标城市和其他城市都不相邻(地图边缘)则加权`
                // 如果一个目标城市的相邻,和出发城市的势力的敌对越多,则降权.
                // 一个目标城市的相邻,和出发城市相邻的己方城市越多,则加权.
                // 举例:南阳有6个相邻,除襄阳之外,的5个城市都是曹操的,刘备在襄阳要打南阳,则会被降权
                // 举例:北平同时可以选择相同条件的南皮和襄平时,如果打下襄平,襄平敌人为0,南皮敌人为4,所以南皮相对襄平减分.
                float neighbor_threat = 0;
                int neighbor_rank = 0;

                auto dst_near_building_list = ai::base_near_baselist[dst_id];
                for (int j = 0; j < dst_near_building_list.count; j++)
                {
                    int neighbor_base_id = dst_near_building_list[j].get_id();
                    if (neighbor_base_id == -1 or neighbor_base_id >= 据点_末)
                        continue;

                    //此处顺序一定不能写错,指的是,邻居据点是否可以攻击此据点的意思
                    if (ch::get_mid_base_id(neighbor_base_id, dst_id).first == -1 and pk::get_building_distance(neighbor_base_id, dst_id) == 2)
                        continue;

                    if (unit_distance[dst_id][neighbor_base_id] > 8) continue;

                    pk::building @neighbor_base = pk::get_building(neighbor_base_id);
                    bool 大城市 = (neighbor_base.facility == 设施_都市);
                    float 水路影响 = 0;

                    if (neighbor_base_id == dst_id)
                        continue;

                    int neighbor_base_rank = ai::force_list.index_of(pk::get_force(pk::get_building(neighbor_base_id).get_force_id()));

                    // 附近有空城则-1
                    if (pk::get_building(neighbor_base_id).get_force_id() == -1)
                    {
                        neighbor_threat -= 1;
                        continue;
                    }

                    // 计数和自己敌对的相邻据点
                    if (pk::get_building(neighbor_base_id).get_force_id() > -1 and !dst_base.is_player())
                    {

                        neighbor_threat += ai::base_atk_power[neighbor_base_id] / 20;

                        if (调试模式.v)
                            pk::trace(" 战略威胁战力计算:目的地:" + pk::decode(pk::get_name(dst_base)) + "  邻居:" + pk::decode(pk::get_name(neighbor_base)) + "  威胁值" + neighbor_threat);

                        // 势力排名越靠前,越威胁大.
                        if (大城市)
                            neighbor_threat += (1 - float(neighbor_base_rank) / float(force_count)) * ((src_rank <= 1) ? 10 : 20);
                        else
                            neighbor_threat += (1 - float(neighbor_base_rank) / float(force_count)) * ((src_rank <= 1) ? 5 : 10);

                        if (调试模式.v)
                            pk::trace(" 战略威胁势力计算:目的地:" + pk::decode(pk::get_name(dst_base)) + "  邻居:" + pk::decode(pk::get_name(neighbor_base)) + "  威胁值" + neighbor_threat);
                    }
                }
                // 地图边缘的城市或者狭隘要地的城市减分
                if (dst_near_building_list.count <= 3)
                {
                    neighbor_threat -= ((3 - dst_near_building_list.count) * 10 + 10);
                }

                weight[dst_id] -= int(pk::min(neighbor_threat, 100.0));

                if (调试模式.v)
                    pk::trace(" 战略要素:目的地:" + pk::decode(pk::get_name(dst_base)) + "  分数:" + weight[dst_id] + "  威胁值" + neighbor_threat);

            }

            building_list.sort(function(a, b) {
                return main.weight[a.get_id()] > main.weight[b.get_id()];
            });

            //清空
            for (int i = 0; i < building_list.count; i++)
            {
                pk::trace(pk::decode(pk::get_name(force)) + " 军:目的地:" + pk::decode(pk::get_name(building_list[i])) + "  分数:" + weight[building_list[i].get_id()]);
            }


            return building_list;
        }


    }

    Main main;
}